

#include "Application.h"
#include "Camera.h"

void ProcessInput(GLFWwindow *window, GL::Camera *camera)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
    {
        glfwSetWindowShouldClose(window, true);
    }
    else if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
    {
        camera->Move(GL::Axis::Z);
    }
    else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
    {
        camera->Move(GL::Axis::z);
    }
    else if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
    {
        camera->Move(GL::Axis::x);
    }
    else if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
    {
        camera->Move(GL::Axis::X);
    }
}

namespace GL
{
    double xpos, ypos;
    Application::Application()
    {
        Start();
    }

    Application::~Application()
    {
        glfwTerminate();
    }

    int Application::Start()
    {
        glfwInit();

        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
        glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
#ifdef __APPLE__
        glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
        m_Window = glfwCreateWindow(m_Data.Width, m_Data.Height, m_Data.Title.c_str(), nullptr, nullptr);

        glfwSetWindowUserPointer(m_Window, &m_Data);
        glfwMakeContextCurrent(m_Window);

        if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
        {
            GL_ERROR("Failed to initialize GLAD");

            return -1;
        }
        glEnable(GL_DEPTH_TEST);

        glViewport(0, 0, m_Data.Width, m_Data.Height);
        GL_INFO("Create Window Success!!");

        glfwSetInputMode(m_Window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
        glfwSetCursorPosCallback(m_Window, [](GLFWwindow *window, double xPos, double yPos)
                                 {
                                     xpos = xPos;
                                     ypos = yPos;
                                 });
        return 0;
    }

    void Application::Run()
    {
        const std::string cubeShader = "D:/learnCode/open-gl/resource/cube.shader";
        const std::string lightShader = "D:/learnCode/open-gl/resource/light.shader";
        Cube *cube = new Cube(cubeShader);
        Light *light = new Light(lightShader);
        Camera *camera = new Camera();

        glm::vec3 lightPos(0.0f, 0.0f, 0.8f);
        glm::vec3 lightColor = glm::vec3(1.0f, 1.0f, 1.0f);
        glm::vec3 objectColor = glm::vec3(1.0f, 0.5f, 0.31f);
        cube->SetUniform3fv("lightColor", lightColor);
        cube->SetUniform3fv("objectColor", objectColor);
        cube->SetUniform3fv("lightPos", lightPos);
        light->SetUniform3fv("lightColor", lightColor);

        light->SetTranslate(lightPos);
        glm::vec3 scale(0.2f);
        light->SetScale(scale);

        glm::mat4 view;
        while (!glfwWindowShouldClose(m_Window))
        {

            float now = glfwGetTime();
            detalTime = now - lastUpdateTime;
            lastUpdateTime = now;

            glfwPollEvents();
            glClearColor(0.2f, 0.3f, 0.3f, 1.0f);

            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

            ProcessInput(m_Window, camera);
            camera->SetCursorPoint(xpos, ypos);
            camera->SetSpeed(2.5f * detalTime);
            camera->Update();
            cube->GetRenderer()->SetViewMatrix(camera->GetView());
            light->GetRenderer()->SetViewMatrix(camera->GetView());

            light->Update();
            cube->Update();

            glfwSwapBuffers(m_Window);
        }
    }

    Application *CreateApplication()
    {
        return new Application();
    };

}